package br.com.massai.view.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.apache.commons.mail.EmailAttachment;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.apache.commons.mail.MultiPartEmail;
import org.apache.commons.mail.SimpleEmail;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import br.com.massai.model.exceptions.ErrorCore;
import br.com.massai.model.exceptions.SystemException;

public class SendMailUtil {
	
	private static final Logger logger = LogManager.getLogger(SendMailUtil.class);
	
	/**
	 * Tipo MIME do email enviado.
	 */
	private static final String CONTENT_TYPE = "text/html";

	/**
	 * Protocolo de envio de email.
	 */
	private static final String MAIL_PROTOCOLO = "mail.smtp.host";

	/**
	 * Envia um e-mail.
	 *
	 * @param destinatario
	 *            o endereço de destino do e-mail
	 * @param remetente
	 *            o endereço de origem do e-mail
	 * @param assunto
	 *            o assunto do e-mail
	 * @param mensagem
	 *            a mensagem do e-mail
	 * @param smtp
	 *            o endereço ip do servidor SMTP
	 */
	public static void enviarEmail(String destinatario, String remetente,
			String assunto, String mensagem, String smtp) {

		SimpleEmail email = new SimpleEmail();

		try {
			email.setHostName(smtp);
			email.addTo(destinatario);
			email.setFrom(remetente);
			email.setSubject(assunto);
			email.setMsg(mensagem);
			
			email.setSmtpPort(465);
			email.setAuthentication("diogojpb", "06673668490diogo-");
			email.setSSL(true);
			email.setTLS(true);
			
			email.send();

		} catch (EmailException e) {
			logger.error(e.getMessage(), e);
		}
	}

	/**
	 * Envia um e-mail com cópia para outro destinatario.
	 *
	 * @param destinatario
	 *            o endereço de destino do e-mail
	 * @param destinatarioCopia
	 *            o endereço de destino para copia do e-mail
	 * @param remetente
	 *            o endereço de origem do e-mail
	 * @param assunto
	 *            o assunto do e-mail
	 * @param mensagem
	 *            a mensagem do e-mail
	 * @param smtp
	 *            o endereço ip do servidor SMTP
	 */
	public static void enviarEmail(List<String> destinatarios, String remetente,
			String assunto, String mensagem, String smtp) {

		SimpleEmail email = new SimpleEmail();

		try {
			email.setHostName(smtp);
			for(String destinatario:destinatarios)
				email.addTo(destinatario);
			email.setFrom(remetente);
			email.setSubject(assunto);
			email.setMsg(mensagem);

			email.setSmtpPort(465);
			email.setAuthentication("diogojpb", "06673668490diogo-");
			email.setSSL(true);
			email.setTLS(true);

			email.send();

		} catch (EmailException e) {
			logger.error(e.getMessage(), e);
		}
	}
	
	/**
	 *
	 * @param destinatario
	 *            o endereço de destino do e-mail
	 * @param destinatarioCopia
	 *            o endereço de destino para copia do e-mail
	 * @param remetente
	 *            o endereço de origem do e-mail
	 * @param assunto
	 *            o assunto do e-mail
	 * @param mensagem
	 *            a mensagem do e-mail em formato HTML
	 * @param smtp
	 *            o endereço ip do servidor SMTP
	 */
	public static void enviarEmailHTML(String destinatario, String remetente, String assunto, String mensagemHtml, String mensagemAlternativa, String smtp) {
		HtmlEmail email = new HtmlEmail();

		try {
	        email.setHtmlMsg(mensagemHtml);

	        email.setHostName(smtp);
	        email.addTo(destinatario);
	        email.setFrom(remetente, "Massai - Portal da Produtividade");
	        email.setSubject(assunto);

	        email.setAuthentication("diogojpb", "06673668490diogo-");
	        email.setSmtpPort(465);
	        email.setSSL(true);
	        email.setTLS(true);

	        email.send();

		} catch (EmailException e) {
			logger.error(e.getMessage(), e);
		}
	}



	/**
	 * Envia um e-mail com anexo.
	 *
	 * @param destinatario
	 *            o endereço de destino do e-mail
	 * @param remetente
	 *            o endereço de origem do e-mail
	 * @param assunto
	 *            o assunto do e-mail
	 * @param mensagem
	 *            a mensagem do e-mail
	 * @param smtp
	 *            o endereço ip do servidor SMTP
	 * @param pathArquivoAnexo
	 *            path do diretório em que se encontra o arquivo a ser anexado
	 * @param nomeArquivo
	 *            nome do arquivo a ser anexado
	 */
	public static void enviarEmailComAnexo(String destinatario,
			String remetente, String assunto, String mensagem, String smtp,
			String pathArquivoAnexo, String nomeArquivo) {

		EmailAttachment attachment = new EmailAttachment();
		attachment.setPath(pathArquivoAnexo);
		attachment.setDisposition(EmailAttachment.ATTACHMENT);
		attachment.setDescription(assunto);
		attachment.setName(nomeArquivo);

		MultiPartEmail email = new MultiPartEmail();
		email.setHostName(smtp);

		try {
			email.addTo(destinatario);
			email.setFrom(remetente);
			email.setSubject(assunto);
			email.setMsg(mensagem);
			email.attach(attachment);
			email.send();

		} catch (EmailException e) {
			logger.error(e.getMessage(), e);
		}
	}
	/**
	 * Envia um e-mail com anexo.
	 *
	 * @param destinatario
	 *            o endereço de destino do e-mail
	 * @param remetente
	 *            o endereço de origem do e-mail
	 * @param assunto
	 *            o assunto do e-mail
	 * @param mensagem
	 *            a mensagem do e-mail
	 * @param smtp
	 *            o endereço ip do servidor SMTP
	 * @param pathArquivoAnexo
	 *            path do diretório em que se encontra o arquivo a ser anexado
	 * @param nomeArquivo
	 *            nome do arquivo a ser anexado
	 * @throws MessagingException
	 */
	public static void enviarEmailComAnexo(String destinatario,
			String remetente, String assunto, String mensagem, String smtp,
			InputStream anexo, String nomeArquivo,String contentType) throws MessagingException {

		try {

			MimeBodyPart corpo = new MimeBodyPart();
			corpo.setText(mensagem);

			Multipart multiPart = new MimeMultipart();
			multiPart.addBodyPart(corpo);

			SendMailUtil mailUtil = new SendMailUtil();

			MimeBodyPart messageBodyPart = new MimeBodyPart();
			messageBodyPart.setDataHandler(
				new DataHandler(mailUtil.new InputStreamDataSource(nomeArquivo,contentType,anexo)));
			messageBodyPart.setFileName(nomeArquivo);

			multiPart.addBodyPart(messageBodyPart);

			Properties props = obterPropertiesMail(smtp);
			Session session = Session.getDefaultInstance(props, null);
			session.setDebug(false);

			Message email = new MimeMessage(session);

			Address to[] = preencherDestinatarios(new String[]{destinatario});

			email.setFrom(new InternetAddress(remetente));
			email.setSubject(assunto);
			email.setRecipients(Message.RecipientType.TO, to);
			email.setContent(multiPart);

			Transport.send(email);
			Thread.sleep(10);

		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
	}
	
	/**
	 * 
	 * @param destinatario
	 * @param remetente
	 * @param assunto
	 * @param mensagem
	 * @param smtp
	 * @param pathArquivoAnexo
	 * @param nomeArquivo
	 */
	public static void enviarHtmlEmailComAnexo(String destinatario,
			String remetente, String assunto, String mensagem, String smtp,
			String pathArquivoAnexo, String nomeArquivo) {

				
		EmailAttachment attachment = new EmailAttachment();
		attachment.setPath(pathArquivoAnexo);
		attachment.setDisposition(EmailAttachment.ATTACHMENT);
		attachment.setDescription(assunto);
		attachment.setName(nomeArquivo);		

		try {
			  HtmlEmail email = new HtmlEmail();
			  email.setHostName(smtp);
			  email.addTo(destinatario);
			  email.setFrom(remetente);
			  email.setSubject(assunto);
			  email.setHtmlMsg(mensagem);
			  email.attach(attachment);
			  email.send();

		} catch (EmailException e) {
			logger.error(e.getMessage(), e);
		}
	}

	/**
	 * Envia uma mensagem de email a varios destinatarios.
	 *
	 * @param mensagem
	 *            mensagem a ser enviado no corpo do email
	 * @param mailTo
	 *            conjunto de emails dos destinatarios
	 * @param mailFrom
	 *            email do remetente
	 * @param subject
	 *            assunto do email
	 * @param ipServidor
	 *            endereço ip do servidor SMTP
	 *
	 * @throws SystemException
	 *             caso ocorra algum erro ao enviar o e-mail
	 */
	@Deprecated
	public static void postMail(String mensagem, String[] mailTo,
			String mailFrom, String subject, String ipServidor)
			throws SystemException {

		try {

			Address to[] = preencherDestinatarios(mailTo);
			InternetAddress addressFrom = new InternetAddress(mailFrom);

			Properties props = obterPropertiesMail(ipServidor);
			Session session = Session.getDefaultInstance(props, null);
			session.setDebug(false);

			Message msg = new MimeMessage(session);
			msg.setFrom(addressFrom);
			msg.setSubject(subject);
			msg.setContent(mensagem, CONTENT_TYPE);
			msg.setRecipients(Message.RecipientType.TO, to);

			Transport.send(msg);
			Thread.sleep(10);

		} catch (Exception e) {
			throw new SystemException(ErrorCore.ERROR_SEND_EMAIL, e);
		}
	}

	/**
	 * Retorna um Properties contendo as propriedades necessarias para a
	 * inicialização de uma sessão com um servidor SMTP.
	 *
	 * @param ip
	 *            uma String contendo o endereço IP do servidor SMTP
	 * @return um Properties contendo as propriedades necessarias para a
	 *         inicialização de uma sessão com um servidor SMTP
	 */
	private static Properties obterPropertiesMail(String ip) {

		Properties props = new Properties();
		props.put(MAIL_PROTOCOLO, ip);

		return props;
	}

	/**
	 * Preenche uma lista de objetos Address a partir de um array de Strings
	 * contendo os emails dos destinatarios.
	 *
	 * @param mailTo
	 *            lista de emails dos destinatarios
	 * @return um array de objetos Address preenchidos com os emails dos
	 *         destinatarios
	 *
	 * @throws AddressException
	 *             caso ocorra algum exceção ao criar o array de Adress
	 */
	private static Address[] preencherDestinatarios(String[] mailTo)
			throws AddressException {

		Address to[] = new InternetAddress[mailTo.length];

		for (int i = 0; i < to.length; i++) {
			to[i] = new InternetAddress(mailTo[i]);
		}
		return to;
	}

	private class InputStreamDataSource implements DataSource {

        private String name;
        private String contentType;
        private ByteArrayOutputStream baos;

        InputStreamDataSource(String name, String contentType, InputStream inputStream) throws IOException {
            this.name = name;
            this.contentType = contentType;

            baos = new ByteArrayOutputStream();

            int read;
            byte[] buff = new byte[256];
            while((read = inputStream.read(buff)) != -1) {
                baos.write(buff, 0, read);
            }
        }

        public String getContentType() {
            return contentType;
        }

        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(baos.toByteArray());
        }

        public String getName() {
            return name;
        }

        public OutputStream getOutputStream() throws IOException {
            throw new IOException("Cannot write to this read-only resource");
        }
    }

}
